package main;
import java.util.Iterator;
import java.util.*;
import org.apache.uima.*;
import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.jcas.JCas;
import java.lang.reflect.*;

import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.jxpath.*;
import org.apache.commons.jxpath.xml.DocumentContainer;


public class typeMappingAnalysisEngineAnnotator extends JCasAnnotator_ImplBase {

	private static String XML_FILE = "xmlFile";
	private String sourceTypeStr;
	private String targetTypeStr;
	private Iterator<String> targetItr;
	private String constraint;
	private LinkedList<Rule> rules = new LinkedList<Rule>();
	private static URL urlXmlFile;
	
//On suppose que le fichier Xml est contenu dans le répertoire resources situé dans le path du projet
	public void initialize(UimaContext context) 
	{
		
		try {
			//Récupération du paramètre, le nom du fichier XML
			XML_FILE = (String) context.getConfigParameterValue(XML_FILE);
			String strUrl = "file://"+System.getProperty("user.dir")+"/resources/"+XML_FILE;
			//Création d'une URL à partir de ce nom
			urlXmlFile = new URL(strUrl);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		
		//Création d'un DocumentContainer contenant notre fichier Xml
		DocumentContainer monDoc = new DocumentContainer(urlXmlFile);
		//Création d'un JXPathContext à partir de ce DocumentContainer
		JXPathContext jxpathContext = JXPathContext.newContext(monDoc);
		Iterator itRules = jxpathContext.iterate("//RULE");
		System.out.println("Nombre de règles "+jxpathContext.selectNodes("//RULE").size());
		
		int i = 0;
		while(itRules.hasNext())
		{
			i++;
			itRules.next();
			System.out.println("<<<REGLE n°"+i+">>>");
			//SOURCE
			String xpath = "//RULE["+i+"]/SOURCE";
			sourceTypeStr = (String)jxpathContext.getValue(xpath);
			
			//TARGET
			xpath = "//RULE["+i+"]/TARGET";
			targetItr = jxpathContext.iterate(xpath);
			ArrayList<String> aL = new ArrayList<String>();
			while(targetItr.hasNext()){
				String tgt = targetItr.next();
				System.out.println("Target de la règle "+i+": "+tgt);
				aL.add(tgt);
			}
			
			//CONSTRAINT
			xpath= "//RULE["+i+"]/CONSTRAINT";
			try{
			constraint = (String)jxpathContext.getValue(xpath);
			}catch(JXPathNotFoundException e){
				constraint = null;
			}
			System.out.println("Taille de l'Array avant l'ajout: "+aL.size());
			//AJOUT A LA LISTE
			rules.add(new Rule(sourceTypeStr,aL,constraint));
		}
	}

	
	public void process(JCas aJCas) throws AnalysisEngineProcessException {
	
	Iterator<Rule> itRules = rules.iterator();
	Rule r;
	while(itRules.hasNext())
	{
		r = itRules.next();
		
		sourceTypeStr = r.getSourceType();
		//Récupération du type source
		Type typeSrc = aJCas.getTypeSystem().getType(sourceTypeStr);

		//Dans le cas où le type source n'existe pas		
		if (typeSrc == null)
		{
			String errmsg = "Le type " + sourceTypeStr + " n'est pas déclaré dans le TypeSystem !";
		    throw new AnalysisEngineProcessException(errmsg, new Object[]{typeSrc});			
		}
		
		//EXECUTION NORMALE
		try{
		//Génération des classes correspondants aux Strings sourceTypeStr et targetTypeStr
		Class SrcClass = Class.forName(sourceTypeStr);
		//Génération des constructeurs des classes source
		Constructor srcConstr = SrcClass.getConstructor(new Class [] {JCas.class});
		//Récupération de l'ensemble/index des annotations du type source
		AnnotationIndex idxSrc = (AnnotationIndex)aJCas.getAnnotationIndex(typeSrc);
		//Création d'un itérateur sur cet index
		Iterator itSrc = idxSrc.iterator();
		
			//Tant qu'il y a des annotations de type source
			while(itSrc.hasNext())
			{
				//Création de l'annotation courante
				Object s = srcConstr.newInstance(new Object [] {aJCas});
				s = itSrc.next();
				SrcClass.cast(s);	//On caste l'objet en type de SrcClass
				
				//On place l'environnement sur l'annotation source courante
				JXPathContext jxpathContext = JXPathContext.newContext(s);

				//Récupération de la contrainte
				String constraint = (String)r.getConstraint();

				if(((constraint!=null)&&(jxpathContext.selectNodes(constraint).size()!=0)) || constraint==null){
					Object[] args = null;

					//Récupération du début de l'annotation courante
					int begin = (Integer)jxpathContext.getValue("begin");
							
					//Récupération du début de l'annotation courante
					int end = (Integer)jxpathContext.getValue("end");
							
					//Récupération du Covered text de l'annotation courante
					String coveredText = (String)jxpathContext.getValue("coveredText");
							
					System.out.println("text: begin "+begin+" end "+end+" coveredText "+coveredText);
					
					ArrayList<String> targetArray = r.getTargetType();
					for(int i=0; i<targetArray.size();i++){
						targetTypeStr = targetArray.get(i);
						
						Class TgtClass = Class.forName(targetTypeStr);
						
						//Génération des constructeurs des classes source/target
						Constructor tgtConstr = TgtClass.getConstructor(new Class [] {JCas.class});
						//Création d'une annotation du type target
						Object t = tgtConstr.newInstance(new Object [] {aJCas});
						TgtClass.cast(t);
						jxpathContext = JXPathContext.newContext(t);
						//Récupération de la méthode addToIndexes de la classe target
						Method addToIndexes = TgtClass.getMethod("addToIndexes", new Class[] {});
						
						//Ajouts à l'annotation du type target
						jxpathContext.setValue("begin", begin);
						jxpathContext.setValue("end", end);
						addToIndexes.invoke(t,args);
					}
				
			
				}
				
			}
		}
				catch (IllegalArgumentException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
				catch (IllegalAccessException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
				catch (InvocationTargetException e) 
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
	}
